/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package trabalhopmforçadesenha;

/**
 *
 * @author Gustavo-Note
 */
public class Metodo2 extends Metodo {
    
    private final int MULTIPLICADOR_TAMANHO_SENHA = 4;
    private final int MULTIPLICADOR_NUMERO_DE_MAIUSCULAS = 2;
    private final int MULTIPLICADOR_NUMERO_DE_MINUSCULAS = 2;
    private final int MULTIPLICADOR_NUMERO_DE_DIGITOS = 4;
    private final int MULTIPLICADOR_NUMERO_DE_SIMBOLOS = 6;
    private final int MULTIPLICADOR_NUMERO_DE_DIGITOS_OU_SIMBOLOS_NO_MEIO = 2;
    
    private final int MULTIPLICADOR_SEQUENCIA_DE_3_LETRAS = 3;
    private final int MULTIPLICADOR_SEQUENCIA_DE_3_NUMEROS = 3;
    private final int MULTIPLICADOR_SEQUENCIA_DE_3_SIMBOLOS = 3;
    
    private final int MULTIPLICADOR_POR_MAIUSCULAS_CONSECUTIVAS = 2;
    private final int MULTIPLICADOR_POR_MINUSCULAS_CONSECUTIVAS = 2;
    private final int MULTIPLICADOR_POR_NUMEROS_CONSECUTIVOS = 2;
    private final int MULTIPLICADOR_POR_SIMBOLOS_CONSECUTIVOS = 2;
    
    private final int TAMANHO_MINIMO_REQUERIDO = 8;
    private final int NUMERO_DE_MAIUSCULAS_REQUERIDO = 1;
    private final int NUMERO_DE_MINUSCULAS_REQUERIDO = 1;
    private final int NUMERO_DE_DIGITOS_REQUERIDOS = 1;
    private final int NUMERO_DE_SIMBOLOS_REQUERIDO = 1;
    
    private int MULTIPLICADOR_REQUERIMENTOS_ATENDIDOS = 2;
    
    private int numMaiusculas = 0;
    private int numMinusculas = 0;
    private int numDigitos = 0;
    private int numSimbolos = 0;
    private int requerimentosAtendidos = 0;
    
    public Metodo2(String senha){
        super(senha);
        
        MAXIMO_PONTOS_PARA_SENHA_MUITO_FRACA = 19;
        MAXIMO_PONTOS_PARA_SENHA_FRACA = 39;
        MAXIMO_PONTOS_PARA_SENHA_MEDIA = 59;
        MAXIMO_PONTOS_PARA_SENHA_FORTE = 79;
    }

    @Override
    public ForcaSenha checarForcaSenha() {
        int pontos = 0;
        
        pontos += obterPontosPorTamanho();
        
        pontos += obterPontosPorMaiuscula();
        pontos += obterPontosPorMinuscula();
        pontos += obterPontosPorNumero();
        pontos += obterPontosPorSimbolo();
        pontos += obterPontosPorNumeroOuSimboloNoMeio();
        
        pontos -= obterPontosPorApenasLetras();
        pontos -= obterPontosPorApenasNumeros();
        
        pontos -= obterPontosPorCaracterRepetido();
        
        pontos -= obterPontosPorMaiusculasConsecutivas();
        pontos -= obterPontosPorMinusculasConsecutivas();
        pontos -= obterPontosPorNumerosConsecutivos();
        
        pontos -= obterPontosPorSequenciaLetras();
        pontos -= obterPontosPorSequenciaNumeros();
        pontos -= obterPontosPorSequenciaSimbolos();
          
        pontos += obterPontosPorRequerimentos();
        
        if(pontos > 100){
            pontos = 100;
        }
        
        this.forca = new ForcaSenha(pontos,super.obterValorForcaSenha(pontos));
        
        return this.forca;
        
    }
    
    private boolean isMaiuscula(char letra){
        return Character.isLetter(letra) && Character.isUpperCase(letra);
    }
    
    private boolean isMinuscula(char letra){
        return Character.isLetter(letra) && Character.isLowerCase(letra);
    }
    
    private boolean isSimbolo(char letra){
        return !Character.isDigit(letra) && !Character.isLetter(letra) && letra != '_';
    }
    
    private int obterPontosPorTamanho(){
        return this.senha.length() * this.MULTIPLICADOR_TAMANHO_SENHA;
    }
    
    private int obterPontosPorMaiuscula(){
        for(int i = 0; i < this.senha.length(); i++){
            if(isMaiuscula(this.senha.charAt(i))){
                numMaiusculas++;
            }                        
        }
        return numMaiusculas > 0 && numMaiusculas < this.senha.length() ? 
                (this.senha.length() - numMaiusculas) * this.MULTIPLICADOR_NUMERO_DE_MAIUSCULAS :
                0;
    }
    
    private int obterPontosPorMinuscula(){
        for(int i = 0; i < this.senha.length(); i++){
            if(isMinuscula(this.senha.charAt(i))){
                numMinusculas++;
            }                        
        }
        return numMinusculas > 0 && numMinusculas < this.senha.length() ? 
                (this.senha.length() - numMinusculas) * this.MULTIPLICADOR_NUMERO_DE_MINUSCULAS :
                0;
    }
    
    private int obterPontosPorNumero(){
        for(int i = 0; i < this.senha.length(); i++){
            if(Character.isDigit(this.senha.charAt(i))){
                numDigitos++;
            }                        
        }
        return numDigitos < this.senha.length()? numDigitos * this.MULTIPLICADOR_NUMERO_DE_DIGITOS : 0;
    }
    
    private int obterPontosPorSimbolo(){
        for(int i = 0; i < this.senha.length(); i++){
            if(isSimbolo(this.senha.charAt(i))){
                numSimbolos++;
            }                        
        }
        return numSimbolos * this.MULTIPLICADOR_NUMERO_DE_SIMBOLOS;
    }
    
    private int obterPontosPorNumeroOuSimboloNoMeio(){
        int pontuacao = 0;
        for(int i = 1; i < this.senha.length() - 1; i++){
            if(Character.isDigit(this.senha.charAt(i)) || isSimbolo(this.senha.charAt(i))){
                pontuacao++;
            }
        }
        return pontuacao * this.MULTIPLICADOR_NUMERO_DE_DIGITOS_OU_SIMBOLOS_NO_MEIO;
    }
    
    private int obterPontosPorMaiusculasConsecutivas(){
        int numMaiusculasConsecutivas = 0;
        for(int i = 0; i < this.senha.length() - 1; i++){
            if(isMaiuscula(this.senha.charAt(i)) && isMaiuscula(this.senha.charAt(i+1))){
                numMaiusculasConsecutivas++;
            }             
        }
        return numMaiusculasConsecutivas * MULTIPLICADOR_POR_MAIUSCULAS_CONSECUTIVAS;
    }
    
    private int obterPontosPorMinusculasConsecutivas(){
        int numMinusculasConsecutivas = 0;
        for(int i = 0; i < this.senha.length() - 1; i++){
            if(isMinuscula(this.senha.charAt(i)) && isMinuscula(this.senha.charAt(i+1))){
                numMinusculasConsecutivas++;
            }             
        }
        return numMinusculasConsecutivas * MULTIPLICADOR_POR_MINUSCULAS_CONSECUTIVAS;
    }
    
    private int obterPontosPorNumerosConsecutivos(){
        int numerosConsecutivos = 0;
        for(int i = 0; i < this.senha.length() - 1; i++){
            if(Character.isDigit(this.senha.charAt(i)) && 
                    Character.isDigit(this.senha.charAt(i+1))){
                numerosConsecutivos++;
            }             
        }
        return numerosConsecutivos * MULTIPLICADOR_POR_NUMEROS_CONSECUTIVOS;
    }

    private int obterPontosPorSequenciaLetras(){
        String letras = "abcdefghijklmnopqrstuvwxyz";
        int sequencias = 0;
        
        for(int i = 0; i < 22;i++){
            String subLetras = letras.substring(i, i+3);
            String subLetrasReverso = new StringBuffer(subLetras).reverse().toString();
            
            if(this.senha.toLowerCase().indexOf(subLetras) != -1 ||
                    this.senha.toLowerCase().indexOf(subLetrasReverso) != -1){
                sequencias++;
            }
        }
        
        return sequencias * this.MULTIPLICADOR_SEQUENCIA_DE_3_LETRAS;
    }
    
    private int obterPontosPorSequenciaNumeros(){
        String numeros = "01234567890";
        int sequencias = 0;
        
        for(int i = 0; i < 8;i++){
            String subNumeros = numeros.substring(i, i+3);
            String subNumerosReverso = new StringBuffer(subNumeros).reverse().toString();
            
            if(this.senha.toLowerCase().indexOf(subNumeros) != -1 ||
                    this.senha.toLowerCase().indexOf(subNumerosReverso) != -1){
                sequencias++;
            }
        }
        
        return sequencias * this.MULTIPLICADOR_SEQUENCIA_DE_3_NUMEROS;
    }
    
    private int obterPontosPorSequenciaSimbolos(){
        String simbolos = ")!@#$%^&*()";
        int sequencias = 0;
        
        for(int i = 0; i < 8;i++){
            String subSimbolos = simbolos.substring(i, i+3);
            String subSimbolosReverso = new StringBuffer(subSimbolos).reverse().toString();
            
            if(this.senha.toLowerCase().indexOf(subSimbolos) != -1 ||
                    this.senha.toLowerCase().indexOf(subSimbolosReverso) != -1){
                sequencias++;
            }
        }
        
        return sequencias * this.MULTIPLICADOR_SEQUENCIA_DE_3_SIMBOLOS;
    }
    
    private int obterPontosPorCaracterRepetido(){
        int numRepetidos = 0,naoRepetidos;
        double pontuacaoRepetidos = 0.0;
        boolean isRepetido;
        for(int i = 0; i < this.senha.length(); i++){
            isRepetido = false;
            for(int j = 0; j < this.senha.length(); j++){
                if(this.senha.charAt(i) == this.senha.charAt(j) && i != j){
                    isRepetido = true;
                    pontuacaoRepetidos += Math.abs((double)this.senha.length()/(j-i));
                }
            }
            if(isRepetido){
                numRepetidos++;
                naoRepetidos = this.senha.length() - numRepetidos;
                pontuacaoRepetidos = (naoRepetidos != 0) ? (int)Math.ceil(pontuacaoRepetidos/naoRepetidos) : 
                        (int)Math.ceil(pontuacaoRepetidos);
            }
        }
        return (int)pontuacaoRepetidos;
    }
    
    private int obterPontosPorApenasLetras(){
        return (numMaiusculas + numMinusculas == this.senha.length()) ? this.senha.length() : 0;
    }
    
    private int obterPontosPorApenasNumeros(){
        return (numDigitos == this.senha.length()) ? this.senha.length() : 0;
    }
    
    private int obterPontosPorRequerimentos(){
        
        if(this.senha.length() >= this.TAMANHO_MINIMO_REQUERIDO){
            this.requerimentosAtendidos++;
        }
        if(numMaiusculas >= this.NUMERO_DE_MAIUSCULAS_REQUERIDO){
            this.requerimentosAtendidos++;
        }
        if(numMinusculas >= this.NUMERO_DE_MINUSCULAS_REQUERIDO){
            this.requerimentosAtendidos++;
        }
        if(numDigitos >= this.NUMERO_DE_DIGITOS_REQUERIDOS){
            this.requerimentosAtendidos++;
        }
        if(numSimbolos >= this.NUMERO_DE_SIMBOLOS_REQUERIDO){
            this.requerimentosAtendidos++;
        }
        
        int numMinimoRequerimentos;
        
        if(this.senha.length() >= this.TAMANHO_MINIMO_REQUERIDO){
            numMinimoRequerimentos = 3;
        }
        else{
            numMinimoRequerimentos = 4;
        }
        
        if(this.requerimentosAtendidos >= numMinimoRequerimentos){
            return requerimentosAtendidos * this.MULTIPLICADOR_REQUERIMENTOS_ATENDIDOS;
        }
        return 0;       
    }
}
